#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <errno.h>
#include <termios.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <getopt.h>
#include <dirent.h>
#include <math.h>

#include <time.h>

#include "license.h"
#include "get_version.h"

/**
 * echo -n '1@3$5^7*qWeRtYuI' | md5sum
 */
#define LICENSE_SHADOW          "6d3cf879a478a65506118fd25227bcd8"

#define LICENSE_MONTH_MIN       (0)
#define LICENSE_MONTH_MAX       (12 * 10)       /* 10 years */

typedef enum {
        OP_NULL,
        OP_GENERIC,
        OP_DISPATCH,
        OP_SNIFFER,
        OP_RECYCLE,
        OP_LIST,
        OP_CONFIRM,
} admin_op_t;

static void usage()
{
        fprintf(stderr, "\nusage: license_dispatch [-h] [-s] [-i <dir> -l <hosts>] [-i <dir> -d <hosts>]\n"
                "\t-h, --help           Show this help\n"
                "\t-s, --sniffer        sniffer machine infomation\n"
                "\t-r, --recycle        recycle node license to manage\n"
                "\t-l, --list           list all node license\n"
                "\t-d, --dispatch       dispatch license\n"
                "\t-i, --infile         specify license directory\n"
                "\t-c, --confirm        confirm file validity\n"
               );
}

static int __get_sniffer(char *path, long *capacity, time_t *time)
{
        int ret;

        ret = license_get_capacity(path, capacity);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = license_get_time(path, time);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}

static int __is_dispatch(char *path, int *is_dispatch, int *is_free, long sniffer_capa, long *permit, int *is_offline)
{
        int fd, ret;
        char buf[MAX_LINE_LEN], *tmp, *time_index, *capa_index, *offline_index;
        struct tm tm_time;

        *is_dispatch = 1;
        *is_free = 0;
        *permit = 0;
        *is_offline = 0;

        fd = open(path, O_RDONLY);
        if (fd < 0) {
                ret = errno;
                GOTO(err_ret, ret);
        }

        ret = read(fd, buf, sizeof(buf));
        if (ret == -1) {
                ret = errno;
                GOTO(err_close, ret);
        }

        close(fd);

        time_index = strstr(buf, "Free license, license expiration time:");
        if (time_index != NULL) {
                *is_free = 1;
        }

        offline_index = strstr(buf, "Node offline.");
        if (offline_index != NULL) {
                *is_dispatch = 1;
                *is_offline = 1;

                goto out;
        }

        tmp = buf;
        time_index = strstr(buf, "license expiration time: ");
        if (time_index != NULL) {
                time_index += strlen("license expiration time: ");
                time_index[strlen("xxxx-xx-xx xx:xx:xx")] = '\0';
                tmp = time_index + strlen("xxxx-xx-xx xx:xx:xx") + 1;
                strptime(time_index, "%Y-%m-%d %H:%M:%S", &tm_time);
#if 0
                if (mktime(&tm_time) - gettime() > DISPATCH_TIME)
                        *is_dispatch = 0;
#endif
        } 

        capa_index = strstr(tmp, "Permit capacity:");
        if (capa_index != NULL) {
                capa_index += strlen("Permit capacity:");
                sscanf(capa_index, "%ldG", permit);
                if (*permit != (long)ceil(sniffer_capa/(1000.0*1000.0*1000.0)))
                        *is_dispatch = 1;
        }

out:
        return 0;

err_close:
        close(fd);
err_ret:
        return ret;
}

/**
 * Disable line buffer and input echo of stdin
 */
static int __getch()
{
        char ch;
        struct termios old, new;

        (void) tcgetattr(STDIN_FILENO, &old);

        memcpy(&new, &old, sizeof(struct termios));
        new.c_lflag &= ~(ICANON | ECHO);

        (void) tcsetattr(STDIN_FILENO, TCSANOW, &new);

        ch = getchar();

        (void) tcsetattr(STDIN_FILENO, TCSANOW, &old);

        return ch;
}

static int __enter_pass(char *pass, int len)
{
        int i, j;
        char ch;

        printf("Password: ");

        for (i = 0, j = 0; i < len - 1; ++i) {
                ch = __getch();

                if (ch == '\n' || ch == '\r')
                        break;

                if (ch == 0x7f) { /* Backspace */
                        --i;
                        if (j)
                                --j;
                } else {
                        pass[j++] = ch;
                }
        }
        pass[j] = 0;

        printf("\n");

        return 0;
}

static int __enter_month(int *_month)
{
        int ret, month = 0, i = 0;
        char buf[MAX_BUF_LEN];

        printf("Validity of License (in months): ");

        if (!fgets(buf, MAX_BUF_LEN, stdin)) {
                month = -1;
        } else {
                while(buf[i]) {
                        if (i != 0 && buf[i] == '\n') {
                        } else if (buf[i] < '0' || buf[i] > '9') {
                                fprintf(stderr, "Invalid month, valid region of month is [%d~%d], 0 means permanent\n",
                                        LICENSE_MONTH_MIN, LICENSE_MONTH_MAX);
                                ret = EINVAL;
                                GOTO(err_ret, ret);
                        }
                        i++;
                }
                month = atoll(buf);
        }

        if (month < LICENSE_MONTH_MIN || month > LICENSE_MONTH_MAX) {
                fprintf(stderr, "Invalid month, valid region of month is [%d~%d], 0 means permanent\n",
                        LICENSE_MONTH_MIN, LICENSE_MONTH_MAX);
                ret = EINVAL;
                GOTO(err_ret, ret);
        }

        *_month = month;

        return 0;
err_ret:
        return ret;
}

static int __enter_capacity(int *_capacity)
{
        int ret, capacity = 0, i = 0;
        char buf[MAX_BUF_LEN];

        printf("Validity of License (in Gigas, input enter to use info file capacity): ");

        if (!fgets(buf, MAX_BUF_LEN, stdin)) {
                capacity = -1;
        } else {
                while(buf[i]) {
                        if (buf[i] == '\n') {
                        } else if (buf[i] < '0' || buf[i] > '9') {
                                fprintf(stderr, "Invalid capacity, capacity must be a unsigned integer, 0 means infinite\n");
                                ret = EINVAL;
                                GOTO(err_ret, ret);
                        }
                        i++;
                }
                if (buf[0] == '\n')
                        capacity = -1;
                else
                        capacity = atoll(buf);
        }

        *_capacity = capacity;

        return 0;
err_ret:
        return ret;
}

static int __login()
{
        int ret, i;
        unsigned char md[MD5_DIGEST_LENGTH];
        char pass[MAX_BUF_LEN];
        char shadow[MD5_DIGEST_LENGTH * 2] = { 0 };

        ret = __enter_pass(pass, MAX_BUF_LEN);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        MD5((unsigned char *)pass, strlen(pass), md);

        for (i = 0; i < MD5_DIGEST_LENGTH; ++i) {
                snprintf(shadow + strlen(shadow), 3, "%02x", md[i]);
        }

        if (memcmp(LICENSE_SHADOW, shadow, MD5_DIGEST_LENGTH * 2)) {
                fprintf(stderr, "Authentication failure\n");
                ret = EINVAL;
                GOTO(err_ret, ret);
        }

        return 0;
err_ret:
        return ret;
}

//add Parameter _grant --- manage/license.h
static int __decrypt_d(long *capacity, time_t *limit, time_t *expired, const char *path, struct Grant *_grant)
{
        int ret;
        long _capacity, capacity_sum = 0;
        struct stat stbuf;
        DIR *dp;
        FILE *fp;
        struct dirent *dirp;
        char childpath[MAX_PATH_LEN], fmd5[MAX_PATH_LEN];
        time_t time_tmp;
        struct list_head head;
        struct list_node *node, *tmp;
        struct Grant grant = {0};

        ret = stat(path, &stbuf);
        if (ret < 0) {
                ret = errno;
                GOTO(err_ret, ret);
        }

        if (!S_ISDIR(stbuf.st_mode))  {
                ret = ENOTDIR;
                GOTO(err_ret, ret);
        }

        dp = opendir(path);
        if (dp == NULL) {
                ret = errno;
                GOTO(err_ret, ret);
        }

        INIT_LIST_HEAD(&head);
        *expired = 0;

        while ((dirp = readdir(dp)) != NULL) {
                if (strcmp(dirp->d_name, ".") == 0 ||
                    strcmp(dirp->d_name, "..") == 0)
                        continue;

                snprintf(childpath, MAX_PATH_LEN,
                        "%s/%s", path, dirp->d_name);

                ret = stat(childpath, &stbuf);
                if (ret < 0) {
                        ret = errno;
                        GOTO(err_ret, ret);
                }

                if (S_ISDIR(stbuf.st_mode))
                        continue;

                strcpy(fmd5, "md5sum ");
                strcat(fmd5, childpath);

                fp = popen(fmd5, "r");
                fgets(fmd5, MAX_PATH_LEN, fp);
                fmd5[32] = '\0';
                pclose(fp);

                if (list_exists(&head, fmd5)) {
                        unlink(childpath);
                        continue;
                } else {
                        node = malloc(sizeof(struct list_node));
                        strcpy(node->fmd5, fmd5);
                        list_add(&node->hook, &head);
                }

                ret = license_check(childpath, &_capacity, &time_tmp);
                if (unlikely(ret)) {
                        if (time_tmp > *expired)
                                *expired = time_tmp;
                        continue;
                }

                grant.exist_vaild_file = 1;

                if (time_tmp == -1) {
                        if (_capacity == -1) {
                                capacity_sum = -1;
                                break;
                        } else {
                                grant.capacity_grant_count++;
                                capacity_sum += _capacity;
                        }
                }
        }

        list_for_each_entry_safe(node, tmp, &head, hook) {
                list_del(&node->hook);
                free(node);
        }

        closedir(dp);
        *limit = 0;

        if (capacity_sum == 0 || capacity_sum == -1) {

                dp = opendir(path);
                if (dp == NULL) {
                        ret = errno;
                        GOTO(err_ret, ret);
                }

                while ((dirp = readdir(dp)) != NULL) {
                        if (strcmp(dirp->d_name, ".") == 0 ||
                            strcmp(dirp->d_name, "..") == 0)
                                continue;

                        snprintf(childpath, MAX_PATH_LEN,
                                "%s/%s", path, dirp->d_name);

                        ret = license_check(childpath, &_capacity, &time_tmp);
                        if (unlikely(ret))
                                continue;

                        if (_capacity == -1) {
                                capacity_sum = -1;
                                *limit = time_tmp;
                                break;
                        } else if (_capacity > capacity_sum) {
                                capacity_sum = _capacity;
                                *limit = time_tmp;
                        }
                }

                closedir(dp);
        } else {
                *limit = -1;
        }

        *_grant = grant;
        *capacity = capacity_sum * 1000 * 1000 * 1000LL;

        return 0;
err_ret:
        return ret;
}

static int __decrypt(char *license_path, char *hosts_path)
{
        int ret, len, is_dispatch, is_free, is_offline;
        long capa_permit = 0, sniffer_capa = 0, permit_capa = 0, host_capa = 0;
        char sniffer_path[MAX_PATH_LEN], liclist_path[MAX_PATH_LEN];
        char host_line[MAX_LINE_LEN], *tmp;
        FILE *fp;
        time_t limit, expired, time;
        struct tm *tm_limit, t;
        char buf[MAX_INFO_LEN];
        int expire_flag = 0;
        struct Grant grant = {0};

        fp = fopen(hosts_path, "r");
        if (fp == NULL) {
                ret = errno;
                GOTO(err_ret, ret);
        }

        ret = __decrypt_d(&capa_permit, &limit, &expired, license_path, &grant);
        if (unlikely(ret))
                GOTO(err_close, ret);

        if (limit == -1) {
                printf("Permanent free license.\n");
        } else if (limit != 0) {
                tm_limit = localtime_r(&limit, &t);
                strftime(buf, MAX_INFO_LEN, "%F %T", tm_limit);
                printf("license expiration time: %s\n", buf);
        } else if (expired != 0) {
                tm_limit = localtime_r(&expired, &t);
                strftime(buf, MAX_INFO_LEN, "%F %T", tm_limit);
                printf("license expired time: %s\n", buf);
        } else {
		expire_flag = 1;
                printf("License expired\n");
        }

        if (capa_permit == -1) {
                printf("Infinite capacity.\n");
        } else
                printf("capacity:%ldG\n", capa_permit/(1000*1000*1000));

        while (1) {
                if (fgets(host_line, MAX_LINE_LEN, fp) == NULL) {
                        break;
                }

                len = strlen(host_line);
                if (host_line[len - 1] == '\n')
                        host_line[len - 1] = '\0';

                if (strlen(host_line) == 0)
                        continue;

                tmp = strstr(host_line, " ");
                if (tmp) {
                        *tmp = '\0';
                        tmp++;
                        host_capa = atoll(tmp);
                }

                strcpy(sniffer_path, DIS_PATH"/sniffer/");
                strcat(sniffer_path, host_line);
                strcpy(liclist_path, DIS_PATH"/liclist/");
                strcat(liclist_path, host_line);

                ret = __get_sniffer(sniffer_path, &sniffer_capa, &time);
                if (unlikely(ret)) {
                        printf("%s:shutdown\n", host_line);

                        continue;
                }

                ret = __is_dispatch(liclist_path, &is_dispatch, &is_free, sniffer_capa, &permit_capa, &is_offline);
                if (unlikely(ret)) {
                        printf("%s:shutdown %ldG\n", host_line, (long)ceil(host_capa/(1000.0*1000.0*1000.0)));

                        continue;
                }

                if (is_free) {
                        printf("%s:free %ldG\n", host_line, (long)ceil(sniffer_capa/(1000.0*1000.0*1000.0)));
                } else if (is_offline) {
                        printf("%s:offline %ldG\n", host_line, (long)ceil(sniffer_capa/(1000.0*1000.0*1000.0)));
                } else if (!permit_capa && (expire_flag || sniffer_capa)) {
                        printf("%s:invalid %ldG\n", host_line, (long)ceil(sniffer_capa/(1000.0*1000.0*1000.0)));
                } else {
                        printf("%s:permit %ldG\n", host_line, permit_capa);
                }
        }

        fclose(fp);

        return 0;
err_close:
        fclose(fp);
err_ret:
        return ret;
}

static int __dispatch(char *license_path, char *hosts_path)
{
        int ret, len, is_dispatch, is_free, is_offline, not_get_node_capa;
        long capa_permit = 0, capa_sum = 0, sniffer_capa = 0, permit_capa = 0, host_capa = 0;
        char sniffer_path[MAX_PATH_LEN], liclist_path[MAX_PATH_LEN], dispatch_path[MAX_PATH_LEN];
        char err_lic[MAX_PATH_LEN], host_line[MAX_LINE_LEN], *tmp;
        FILE *fp;
        int err_fd;
        time_t limit, expired, time;
        struct Grant grant = {0};


        fp = fopen(hosts_path, "r");
        if (fp == NULL) {
                ret = errno;
                GOTO(err_ret, ret);
        }

        ret = __decrypt_d(&capa_permit, &limit, &expired, license_path, &grant);
        if (unlikely(ret))
                GOTO(err_close, ret);

	//if there is no effective authorization file in ump/manage/license, then stop this authorization.
        if (grant.exist_vaild_file == 0) {
                printf("%s", "there is no effective authorization file");
                goto back;
        }

        while (1) {
                not_get_node_capa = 0;
                if (fgets(host_line, MAX_LINE_LEN, fp) == NULL) {
                        break;
                }

                len = strlen(host_line);
                if (host_line[len - 1] == '\n')
                        host_line[len - 1] = '\0';

                if (strlen(host_line) == 0)
                        continue;

                tmp = strstr(host_line, " ");
                if (tmp) {
                        *tmp = '\0';
                        tmp++;
                        host_capa = atoll(tmp);
                }

                strcpy(sniffer_path, DIS_PATH"/sniffer/");
                strcat(sniffer_path, host_line);
                strcpy(liclist_path, DIS_PATH"/liclist/");
                strcat(liclist_path, host_line);
                strcpy(dispatch_path, DIS_PATH"/dispatch/");

                ret = __get_sniffer(sniffer_path, &sniffer_capa, &time);
                if (unlikely(ret)) {
                        not_get_node_capa = 1;
                        capa_sum += host_capa;
                }

                ret = __is_dispatch(liclist_path, &is_dispatch, &is_free, sniffer_capa, &permit_capa, &is_offline);
                if (unlikely(ret)) {
                        capa_sum += host_capa;
                        not_get_node_capa = 1;
                }

                capa_sum += sniffer_capa;
                if ((capa_permit != -1 && capa_sum > capa_permit) || (limit != -1 && time > limit)) {
                        strcpy(err_lic, DIS_PATH"/dispatch/");
                        strcat(err_lic, host_line);

                        err_fd = open(err_lic, O_RDWR | O_CREAT | O_TRUNC, 644);
                        if (err_fd < 0)
                                continue;

                        close(err_fd);

			//If capacity is insufficient, then stop this authorization.
			if (capa_permit != -1 && capa_sum > capa_permit) {
                                printf("%s", "distribution capacity is insufficient");
                        } else {
                                printf("%s", "invalid time");
                        }
                        goto back;
                }

                if (is_dispatch && (not_get_node_capa == 0)) {
                        ret = license_encrypt_m(host_line, sniffer_path, dispatch_path, LIMIT_TIME_MON, 1, -1);

                        continue;
                }
        }

back:
        fclose(fp);

        return 0;
err_close:
        fclose(fp);
err_ret:
        return ret;
}

static int __sniffer(char *path)
{
        return license_sniffer(path);
}

static int __get_info(char *ssh_info, char *host_name, int *sum_limit, int *sum_capa,
                      int *is_free, int *is_permanent, int *is_infinite)
{
        int ret, host_capa, i = 0;
        char *time_index, *capa_index, *tmp;
        struct tm tm_time;
        time_t host_time;

        tmp = strstr(ssh_info, "No license found.");
        if (tmp != NULL) {
                fprintf(stderr, "%s:No license found.\n", host_name);
                ret = 1;
                GOTO(err_ret, ret);
        }

        tmp = strstr(ssh_info, "Node offline.");
        if (tmp != NULL) {
                fprintf(stderr, "%s:Node offline.\n", host_name);
                ret = 1;
                GOTO(err_ret, ret);
        }

        tmp = strstr(ssh_info, "License expired.");
        if (tmp != NULL) {
                fprintf(stderr, "%s:License expired.\n", host_name);
                ret = 1;
                GOTO(err_ret, ret);
        }

        tmp = strstr(ssh_info, "Invalid license.");
        if (tmp != NULL) {
                fprintf(stderr, "%s:Invalid license.\n", host_name);
                ret = 1;
                GOTO(err_ret, ret);
        }

        tmp = strstr(ssh_info, "Excess capacity.");
        if (tmp != NULL) {
                fprintf(stderr, "%s:Excess capacity.\n", host_name);
                ret = 1;
                GOTO(err_ret, ret);
        }

        tmp = ssh_info;
        time_index = strstr(tmp, "Free license, license expiration time: ");
        if (time_index != NULL) {
                *is_free = 1;
                goto out;
        }

        time_index = strstr(tmp, "Permanent free license.");
        if (time_index != NULL) {
                if (*sum_limit != -1) {
                        fprintf(stderr, "Other node is not permanent free license but %s\n", host_name);
                        ret = 1;
                        GOTO(err_ret, ret);
                }

                *is_permanent = 1;
        }

        time_index = strstr(tmp, "Valid license, license expiration time: ");
        if (time_index != NULL) {
                time_index += strlen("Valid license, license expiration time: ");
                time_index[strlen("xxxx-xx-xx xx:xx:xx")] = '\0';
                tmp = time_index + strlen("xxxx-xx-xx xx:xx:xx") + 1;
                strptime(time_index, "%Y-%m-%d %H:%M:%S", &tm_time);

                host_time = mktime(&tm_time);
                if (*sum_limit == -1)
                        *sum_limit = host_time;
                else if (abs(host_time - *sum_limit) < FREE_LICENSE)
                        *sum_limit = *sum_limit < host_time ? *sum_limit:host_time;
                else {
                        fprintf(stderr, "The difference in limit time more than 3 months between two nodes\n");
                        ret = 1;
                        GOTO(err_ret, ret);
                }
        }

        capa_index = strstr(tmp, "Infinite capacity.");
        if (capa_index != NULL) {
                if (*sum_capa != -1) {
                        fprintf(stderr, "Other node is not Infinite capacity license but %s\n", host_name);
                        ret = 1;
                        GOTO(err_ret, ret);
                }

                *is_infinite  = 1;
        }

        capa_index = strstr(tmp, "Permit capacity:");
        if (capa_index != NULL) {
                capa_index += strlen("Permit capacity:");
                while (capa_index[i++] != 'G');
                capa_index[i - 1] = '\0';

                host_capa = atoi(capa_index);
                if (*sum_capa == -1)
                        *sum_capa = 0;
                *sum_capa += host_capa;
        }

out:
        return 0;

err_ret:
        return ret;
}

static int __recycle(char *license_path, char *hosts_path, int confirm)
{
        int ret, len, sum_capa = -1, sum_limit = -1, is_free = 0, is_permanent = 0, is_infinite = 0;
        char host_line[MAX_LINE_LEN], ssh_cmd[MAX_INFO_LEN], ssh_info[MAX_BUF_LEN], lic[MAX_PATH_LEN];
        char *tmp;
        FILE *host_fp, *ssh_fd;
        struct tm *tm_limit, t;
        char buf[MAX_INFO_LEN];
        time_t limit;

        strcpy(lic, license_path);
        if (access(lic, F_OK)) {
                fprintf(stderr, "%s not found.\n", lic);
                ret = 1;
                GOTO(err_ret, ret);
        }
        strcat(lic, "/"LICENSE_RECYCLE);
        if (!access(lic, F_OK)) {
                fprintf(stderr, "license already recycled.\n");
                ret = 1;
                GOTO(err_ret, ret);
        }

        host_fp = fopen(hosts_path, "r");
        if (host_fp == NULL) {
                ret = errno;
                GOTO(err_ret, ret);
        }

        while (1) {
                if (fgets(host_line, MAX_LINE_LEN, host_fp) == NULL) {
                        break;
                }

                len = strlen(host_line);
                if (host_line[len - 1] == '\n')
                        host_line[len - 1] = '\0';

                if (strlen(host_line) == 0)
                        continue;

                tmp = strstr(host_line, " ");
                if (tmp) {
                        *tmp = '\0';
                }

                strcpy(ssh_cmd, "ssh ");
                strcat(ssh_cmd, host_line);
                strcat(ssh_cmd, " '/opt/fusionstack/lich/libexec/lich.license -m list'");

                ssh_fd = popen(ssh_cmd, "r");
                ssh_info[0] = '\0';
                fread(ssh_info, MAX_BUF_LEN, 1, ssh_fd);
                pclose(ssh_fd);

                ret = __get_info(ssh_info, host_line,  &sum_limit, &sum_capa, &is_free, &is_permanent, &is_infinite);
                if (unlikely(ret))
                        GOTO(err_close, ret);
        }

        if (is_permanent == 0 && sum_limit == -1 && is_free == 1)
                sum_limit = 0;
        if (is_infinite == 0 && sum_capa == -1 && is_free == 1)
                sum_limit = 0;

        if (!confirm) {
                if (sum_limit != 0 && sum_capa != 0) {
                        if (sum_limit == -1) {
                                printf("Limit time:Permanent\n");
                        } else {
                                limit = sum_limit;
                                tm_limit = localtime_r(&limit, &t);
                                strftime(buf, MAX_INFO_LEN, "%F %T", tm_limit);
                                printf("Limit time:%s\n", buf);
                        }

                        if (sum_capa == -1) {
                                printf("Permit capacity:Infinite\n");
                        } else {
                                printf("Permit capacity:%d\n", sum_capa);
                        }
                } else {
                        printf("No valid license found\n");
                        return 0;
                }

                return 0;
        }

        rewind(host_fp);

        while (1) {
                if (fgets(host_line, MAX_LINE_LEN, host_fp) == NULL) {
                        break;
                }

                len = strlen(host_line);
                if (host_line[len - 1] == '\n')
                        host_line[len - 1] = '\0';

                if (strlen(host_line) == 0)
                        continue;

                tmp = strstr(host_line, " ");
                if (tmp) {
                        *tmp = '\0';
                }

                strcpy(ssh_cmd, "ssh ");
                strcat(ssh_cmd, host_line);
                strcat(ssh_cmd, " 'rm -rf /opt/fusionstack/license'");
                system(ssh_cmd);
        }

        fclose(host_fp);

        if (sum_limit != 0 && sum_capa != 0) {
                __sniffer(TMP_PATH);

                if (sum_limit == -1)
                        sum_limit = 0;
                else
                        sum_limit = sum_limit - time(NULL);

                if (sum_capa == -1)
                        sum_capa = 0;

                ret = license_encrypt_m(LICENSE_RECYCLE, TMP_PATH, license_path, LIMIT_TIME_SEC, sum_limit, sum_capa);
                unlink(TMP_PATH);
        }

        return 0;
err_close:
        fclose(host_fp);
err_ret:
        return ret;
}

static int __encrypt_m(const char *ifile, const char *odir)
{
        int ret, month, capacity;

        ret = __login();
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = __enter_month(&month);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = __enter_capacity(&capacity);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        ret = license_encrypt_m(NULL, ifile, odir, LIMIT_TIME_MON, month, capacity);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}

/**
 * function: Check the validity of the contents of the file
 * return -- EIO(5): Invalid file
 *           other err
 */
static int __confirm(const char *license_path)
{
        int ret;
        long capacity = 0;
        time_t limit;

        ret = license_check(license_path, &capacity, &limit);
        if (unlikely(ret)) {
                goto err_ret;
        }

        return 0;
err_ret:
       unlink(license_path);
        return ret;
}

int main(int argc, char *argv[])
{
        int ret, op = OP_NULL, verbose = 0, confirm = 0;
        char c_opt, *ifile = NULL, *ofile = NULL, *hosts = NULL;

        (void) verbose;

        while (1) {
                int option_index = 0;

                static struct option long_options[] = {
                        { "verbose", 0, 0, 'v' },
                        { "help",    0, 0, 'h' },
                        { "confirm", 0, 0, 'c' },
                        //{ "generic",0, 0, 'g' },
                        { "dispatch",0, 0, 'd' },
                        { "sniffer" ,0, 0, 's' },
                        { "recycle" ,0, 0, 'r' },
                        { "list",    0, 0, 'l' },
                        { "infile",  1, 0, 'i' },
                        { "outfile", 1, 0, 'o' },
                        { 0, 0, 0, 0 },
                };

                c_opt = getopt_long(argc, argv, "vhc:d:sr:l:i:o:", long_options, &option_index);
                if (c_opt == -1)
                        break;

                switch (c_opt) {
                case 'v':
                        get_version();
                        EXIT(0);
                case 'h':
                        usage();
                        EXIT(0);
                case 'c':
                        op = OP_CONFIRM;
                        ifile = optarg;
                        break;
                case 'g':
                        op = OP_GENERIC;
                        break;
                case 'd':
                        op = OP_DISPATCH;
                        hosts = optarg;
                        break;
                case 's':
                        op = OP_SNIFFER;
                        break;
                case 'r':
                        op = OP_RECYCLE;
                        hosts = optarg;
                        break;
                case 'l':
                        op = OP_LIST;
                        hosts = optarg;
                        break;
                case 'i':
                        ifile = optarg;
                        break;
                case 'o':
                        ofile = optarg;
                        break;
                default:
                        usage();
                        EXIT(EINVAL);
                }
        }

        switch (op) {
        case OP_GENERIC:
                if (!ifile) {
                        usage();
                        EXIT(EINVAL);
                }

                ret = __encrypt_m(ifile, ofile);
                if (unlikely(ret))
                        GOTO(err_ret, ret);

                break;
        case OP_DISPATCH:
                if (!ifile) {
                        usage();
                        EXIT(EINVAL);
                }

                ret = __dispatch(ifile, hosts);
                if (unlikely(ret))
                        GOTO(err_ret, ret);

                break;
        case OP_SNIFFER:
                ret = __sniffer(NULL);
                if (unlikely(ret))
                        GOTO(err_ret, ret);

                break;
        case OP_RECYCLE:
                ret = __recycle(ifile, hosts, confirm);
                if (unlikely(ret))
                        GOTO(err_ret, ret);

                break;
        case OP_LIST:
                if (!ifile) {
                        usage();
                        EXIT(EINVAL);
                }

                ret = __decrypt(ifile, hosts);
                if (unlikely(ret))
                        GOTO(err_ret, ret);

                break;
        case OP_CONFIRM:
                if (!ifile) {
                        usage();
                        exit(EINVAL);
                }

                ret = __confirm(ifile);
                if (unlikely(ret))
                        goto err_ret;

                break;
        case OP_NULL:
        default:
                usage();
                EXIT(EINVAL);
        }

        return 0;
err_ret:
        return ret;
}
